#include "os_list.h"
#include "os_def.h"

#if OS_LIST_INFO_ENABLE
#undef OS_DBG_PRINT_ENABLE
#define OS_DBG_PRINT_ENABLE     1       // 强制允许输出
#endif

#define obj_to_list_item(obj, list) ((os_list_item_t *)((uint8_t *)obj + list->owner_offset))
#define list_item_to_obj(item, list) ((void *)((uint8_t *)item - list->owner_offset))

/**
 * 链表完整性检查函数，用于检查整个任务链表是否正确
 * 当发现不正确时，程序死机，卡死在指定的位置
 */
#if OS_LIST_INFO_ENABLE
void os_list_check (os_list_t * list) {
    os_assert(list != OS_NULL);

    os_list_item_t * first = list->first;
    os_list_item_t * last = list->last;

    // 检查list中的first+last+count
    os_assert(list->count >= 0);
    if (list->count == 0) {
        // 为空时，first和last必定为0
        os_assert(!list->first && !list->last);
    } else {
        // 不为空时，二者必定不为0
        os_assert(list->first && list->last);
        if (list->count == 1) {
            os_assert(list->first == list->last);         // 1个，first和last必须相同
        } else {
            os_assert(list->first != list->last);          // 超过1个，不能指向同一个
        }
    }

    // 检查链接关系
    int count = 0;
    for (os_list_item_t * curr = list->first; curr; curr = curr->next) {
        // 不是第一个，pre肯定不为空；否则肯定为空
        if (curr == first) {
            os_assert(curr->pre == OS_NULL);
        } else {
            os_assert(curr->pre != OS_NULL);
        }

        // 不是最后一个，next肯定不为空；否则肯定为空
        if (curr == last) {
            os_assert(curr->next == OS_NULL);
        } else {
            os_assert(curr->next != OS_NULL);
        }

        // 检查前后结点的指向
        if (curr->next) {
            os_assert(curr->next->pre == curr);
        }
        if (curr->pre) {
            os_assert(curr->pre->next == curr);
        }

        // TODO: 可以在此做一些任务结构方面的检查
        count++;
    }

    // 计数要相同
    os_assert(count == list->count);
}
#endif

/**
 * 链表结点初始化
 */
void __os_list_item_init (os_list_item_t * item, int offset) {
    item->pre = item->next = (os_list_item_t *)0;
#if OS_LIST_INFO_ENABLE
    item->owner.owner = (uint8_t *)item - offset;
#endif
}

/**
 * 获取前一结点
 */
void * os_list_item_pre (os_list_t * list, void * obj) {
    os_assert(list != OS_NULL);
    os_assert(obj != OS_NULL);

    os_list_item_t * item = obj_to_list_item(obj, list);
    if (item->pre) {
        return list_item_to_obj(item->pre, list);
    }

    return OS_NULL;
}

/**
 * 获取下一结点
 */
void * os_list_item_next (os_list_t * list, void * obj) {
    os_assert(list != OS_NULL);
    os_assert(obj != OS_NULL);

    os_list_item_t * item = obj_to_list_item(obj, list);
    if (item->next) {
        return list_item_to_obj(item->next, list);
    }

    return OS_NULL;
}

/**
 * 初始化队列
 */
void __os_list_init (os_list_t * list, int owner_offset) {
	list->first = list->last = OS_NULL;
    list->owner_offset = owner_offset;
    list->count = 0;
}

/**
 * 取队列头部结点
*/
void * os_list_first (os_list_t * list) {
    os_assert(list != OS_NULL);

    if (list->first) {
        return list_item_to_obj(list->first, list);
    }

    return OS_NULL;
}

/**
 * 取队列尾结点
*/
void * os_list_last (os_list_t * list) {
    os_assert(list != OS_NULL);

    if (list->last) {
        return list_item_to_obj(list->last, list);
    }

    return OS_NULL;
}

/**
 * 将指定任务添加到队列头部
 * @param list 任务列表
 * @param item 待加入的任务
 */
void os_list_insert_first (os_list_t * list, void * obj) {
    os_assert(list != OS_NULL);
    os_assert(obj != OS_NULL);

    os_list_item_t * item = obj_to_list_item(obj, list);
    os_assert((item->next == OS_NULL) && (item->pre == OS_NULL));

    // 结点本身
    item->pre = OS_NULL;
    item->next = list->first;

    // 如果原来有首结点，则更改其pre；否则作为新的首结点
    if (list->first) {
        list->first->pre = item;
		list->first = item;
    } else {
        // 原链表为空
        list->first = item;
        list->last = item;
    }

    list->count++;
    os_list_check(list);
}

/**
 * 将指定任务添加到队列尾部
 * @param list 任务列表
 * @param item 待加入的任务
 */
void os_list_insert_last (os_list_t * list, void * obj) {
    os_assert(list != OS_NULL);
    os_assert(obj != OS_NULL);

    os_list_item_t * item = obj_to_list_item(obj, list);
    os_assert((item->next == OS_NULL) && (item->pre == OS_NULL));

    // 结点本身
    item->next = OS_NULL;
    item->pre = list->last;

    // 如果原来有尾结点，则更改其next；否则作为新的尾结点
    if (list->last) {
        list->last->next = item;
		list->last = item;
    } else {
        // 原链表为空
        list->first = list->last = item;
    }

    list->count++;
    os_list_check(list);
}

/**
 * 插入一个任务到指定的结点后
 * @param list 待插入的结点
 * @param pre 待插入的结点后
 * @param next 等待被插入的结点
*/
void os_list_insert_after (os_list_t * list, void * pre_obj, void * next_obj) {
    os_assert(list != OS_NULL);
    os_assert(next_obj != OS_NULL);

    // 插入表头
    if (pre_obj == OS_NULL) {
        os_list_insert_first(list, next_obj);
        return;
    }

    os_list_item_t * pre_item = obj_to_list_item(pre_obj, list);
    os_list_item_t * next_item = obj_to_list_item(next_obj, list);
    os_assert((next_item->next == OS_NULL) && (next_item->pre == OS_NULL));

    // 待插入结点本身
    next_item->pre = pre_item;
    next_item->next = pre_item->next;

    // 前后结点，后结点可能存在也可能不存在
    if (pre_item->next) {
        pre_item->next->pre = next_item;
    }
    pre_item->next = next_item;

    // 新的尾结点
    if (list->last == pre_item) {
        list->last = next_item;
    }

    list->count++;

    os_list_check(list);
}

/**
 * 移除列表头部的任务
 * @param list 任务列表
 * @return 移除的任务
 */
void * os_list_remove_first (os_list_t * list) {
    os_assert(list != OS_NULL);

    os_list_item_t * item = OS_NULL;
    if (list->count > 0) {
        // 取第一个结点
        item = list->first;

        // 由于是首结点，所以只要判断next是否有效，有效时修改其pre
        if (item->next) {
            item->next->pre = OS_NULL;
        }

        // 设置下一结点以及其pre
        list->first = item->next;
        if (list->last == item) {
            // 移除的是首结点，且又是末结点，所以此时链表实际是为空的
            list->last = OS_NULL;
        }

        list->count--;

        // 最后配置结点自己
        item->pre = item->next = OS_NULL;
        return list_item_to_obj(item, list);
    }

    os_list_check(list);
    return OS_NULL;
}

/**
 * 移除指定的任务
 * @param list 任务列表
 * @param 待移除的任务
 */
void os_list_remove_item (os_list_t * list, void * obj) {
    os_assert(list != OS_NULL);
    os_assert(obj != OS_NULL);
    os_assert(list->count != 0);

    os_list_item_t * item = obj_to_list_item(obj, list);

    if (item->pre) {
        item->pre->next = item->next;
    }

    if (item->next) {
        item->next->pre = item->pre;
    }

    if (list->first == item) {
        list->first = item->next;
    }

    if (list->last == item) {
        list->last = item->pre;
    }

    item->pre = item->next = OS_NULL;
    list->count--;

    os_list_check(list);
}

/**
 * 清空任务列表，即将其中的任务全部从队列中移除
 * @param list 任务列表
 */
void os_list_remove_all (os_list_t * list) {
    os_assert(list != OS_NULL);

    // 遍历链表，逐个移除所有结点
    os_list_item_t * curr = list->first;
    while (curr) {
        // 注意先将下结点取出来
        os_list_item_t * next = curr->next;

        // 重置结点
        curr->pre = curr->next = OS_NULL;

        // 再处理下一结点
        curr = next;
    }

    // 重置链表结构
    list->first = list->last = OS_NULL;
    list->count = 0;

    os_list_check(list);
}
